package com.ywang.puremvc.impl;

import java.util.Hashtable;
import java.util.Vector;

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.ywang.puremvc.framework.ICommand;
import com.ywang.puremvc.framework.IController;
import com.ywang.puremvc.framework.INotification;

/**
 * @author ywang
 */
public class Controller implements IController {

    private static Controller instance;
    
    CommandExecutor event_handler;
    CommandExecutor io_handler;
    
    Hashtable<Integer, Class<ICommand>> commandMap = new Hashtable<Integer, Class<ICommand>>();
    
    
    public static Controller getInstance() {
        if (instance == null)
            instance = new Controller();
        return instance;
    }
    
    private Controller() {
        event_handler = new CommandExecutor(new HandlerThread("event-handler").getLooper());
        io_handler = new CommandExecutor(new HandlerThread("io-handler").getLooper());
    }
    
    
    @Override
    public void registerCommand(Integer key, Class<ICommand> clazz) {
        commandMap.put(key, clazz);
    }

    @Override
    public int executeCommand(INotification notification) {
        Class<ICommand> clazz = commandMap.get(Integer.valueOf(notification.getId()));
        if (clazz == null)
            return ICommand.NO_COMMAND;
        
        ICommand command;
        try {
            command = clazz.newInstance();
        }
        catch (Exception e) {
            return ICommand.NO_COMMAND;
        }
        command.appendNotification(notification);
        return executeCommand(command);
    }
    
    public int executeCommand(ICommand command) {
        CommandExecutor handler = null;
        switch (command.getType()) {
            default:
            case ICommand.TYPE_EVENT:
                handler = event_handler;
                break;
            case ICommand.TYPE_IO:
                handler = io_handler;
                break;
        }
        handler.addCommand2Queue(command);
        return ICommand.OK;
    }
    
    @Override
    public void removeCommand(Integer key) {
        commandMap.remove(key);
    }
    
    static class CommandExecutor extends Handler {
        
        final int EXECUTE = 0;
        final int CANCEL_ALL = 1;
        
        ICommand executingCommand;
        Vector<ICommand> commandList = new Vector<ICommand>();
        
        CommandExecutor(Looper looper) {
            super(looper);
        }
        
        public void addCommand2Queue(ICommand command) {
            commandList.add(command);
            sendEmptyMessage(EXECUTE);
        }
        
        public void insertCommand2Queue(ICommand command) {
            commandList.insertElementAt(command, 0);
            sendEmptyMessage(EXECUTE);
        }
        
        public void cancelCurrentCommand() {
            ICommand executingCommand = this.executingCommand;
            if (executingCommand != null) {
                executingCommand.cancel();
            }
        }
        
        public void cancelAllCommands() {
            sendEmptyMessage(CANCEL_ALL);
            cancelCurrentCommand();
        }
        
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case EXECUTE:
                    if (commandList.size() > 0) {
                        executingCommand = commandList.firstElement();
                        commandList.removeElement(executingCommand);
                        executingCommand.execute();
                        executingCommand = null;
                    }
                    else {
                        Log.d("puremvc.demo", "no command to execute!");
                    }
                    break;
                case CANCEL_ALL:
                    commandList.removeAllElements();
                    break;
            }
        }
    }
}
